package references

import (
	"HandWritingJVM/instructions/base"
	"HandWritingJVM/rtda"
	"HandWritingJVM/rtda/heap"
)

//调用接口中的方法
type INVOKE_INTERFACE struct {
	index uint
}

func (self *INVOKE_INTERFACE) FetchOperands(reader *base.BytecodeReader) {
	self.index = uint(reader.ReadUint16())
	reader.ReadUint8()
	reader.ReadUint8()
}

func (self *INVOKE_INTERFACE) Execute(frame *rtda.Frame) {
	cp := frame.Method().Class().ConstantPool()
	imr := cp.GetConstant(self.index).(*heap.InterfaceMethodRef)
	resolvedInterfaceMethod := imr.ResolvedInterfaceMethod()
	if resolvedInterfaceMethod.IsStatic() || resolvedInterfaceMethod.IsPrivate() {
		panic("java.lang.IncompatibleClassChangeError")
	}
	ref := frame.OperandStack().GetRefFromTop(resolvedInterfaceMethod.ArgSlotCount() - 1)
	if ref == nil {
		panic("java.lang.NullPointerException")
	}
	//未实现接口
	if !ref.Class().IsImplements(resolvedInterfaceMethod.ResolvedClass()) {
		panic("java.lang.IncompatibleClassChangeError")
	}
	methodToBeInvoked := heap.LookupMethodInClass(ref.Class(), resolvedInterfaceMethod.Name(), resolvedInterfaceMethod.Descriptor())
	if methodToBeInvoked == nil || methodToBeInvoked.IsAbstract() {
		panic("java.lang.AbstractMethodError")
	}
	if !methodToBeInvoked.IsPublic() {
		panic("java.lang.IllegalAccessError")
	}
	base.InvokeMethod(frame, methodToBeInvoked)
}
